<template>
  <div>
    <p class="fixed-top-helper"></p>
    <p class="fixed-top-reference"></p>
    <header>头部</header>
    <main>
      <img v-for="(image, i) in images" :key="i" src :data-img-url="image" />
    </main>
    <footer>底部</footer>
  </div>
</template>

<script>
/** https://segmentfault.com/a/1190000021069054 */
const images = [
  'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1574247890587&di=88d4066be3d57ac962a6bec37e265d37&imgtype=0&src=http%3A%2F%2F01.imgmini.eastday.com%2Fmobile%2F20170810%2F20170810151144_d41d8cd98f00b204e9800998ecf8427e_3.jpeg',
  'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=4054762707,1853885380&fm=26&gp=0.jpg',
  'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1574247912077&di=508a949e5e291875debf6ca844292cd4&imgtype=0&src=http%3A%2F%2F03imgmini.eastday.com%2Fmobile%2F20180827%2F20180827095359_6759372e9bd28026ee6f53b500fb4291_2.jpeg'
];
export default {
  data() {
    return {
      images,
      lazyLoad: {
        target: null,
        observer: null
      },
      touchFooter: {
        target: null,
        observer: null
      },
      stickHeader: {
        target: null,
        reference: null,
        observer: null
      }
    };
  },
  mounted() {
    this.createLazyLoadObserver();
    this.createTouchFooterObserver();
    this.createStickHeaderObserver();
  },
  beforeDestroy() {
    this.unobserveAllIntersectionObservers();
  },
  methods: {
    /*
     * 创建懒加载observer并遍历监听所有img
     */
    createLazyLoadObserver() {
      this.lazyLoad.target = document.querySelectorAll('img');

      this.lazyLoad.observer = new IntersectionObserver(entries => {
        entries.forEach(item => {
          if (item.isIntersecting) {
            item.target.src = item.target.dataset.imgUrl;
          }
        });
      });

      this.lazyLoad.target.forEach(image => {
        this.lazyLoad.observer.observe(image);
      });
    },
    /*
     * 创建触底observer并监听footer
     */
    createTouchFooterObserver() {
      this.touchFooter.target = document.querySelector('footer');

      this.touchFooter.observer = new IntersectionObserver(entries => {
        entries.forEach(item => {
          if (item.isIntersecting) {
            setTimeout(() => {
              console.log('滚动到了底部，可以发request请求数据了');
            }, 2000);
          }
        });
      });

      this.touchFooter.observer.observe(this.touchFooter.target);
    },
    /*
     * 创建吸顶observer并监听header
     * 创建reference首次防抖，.fixed-top-helper二次防抖
     */
    createStickHeaderObserver() {
      this.stickHeader.target = document.querySelector('header');
      this.stickHeader.reference = document.querySelector(
        '.fixed-top-reference'
      );
      this.stickHeader.reference.style.top = `${this.stickHeader.target.offsetTop}px`;

      this.stickHeader.observer = new IntersectionObserver(entries => {
        entries.forEach(item => {
          if (item.boundingClientRect.top < 0) {
            this.stickHeader.target.classList.add('fixed');
          } else {
            this.stickHeader.target.classList.remove('fixed');
          }
        });
      });

      this.stickHeader.observer.observe(this.stickHeader.reference);
    },
    /*
     * 取消observe所有监听目标
     */
    unobserveAllIntersectionObservers() {
      /*
      * disconncet()可以取消所有observed目标
      * 如果调用unobserve取消监听，稍显冗余的代码如下:
        this.lazyLoad.target.forEach((image) => {
          this.lazyLoad.observer.unobserve(image);
        });
      */
      this.lazyLoad.observer.disconnect();
      /*
       * 由于touchFooter和stickHeader只observe了一个目标，因此单独unobserve即可
       * 当然disconnect()也是ok的
       */
      this.touchFooter.observer.unobserve(this.touchFooter.target);
      this.stickHeader.observer.unobserve(this.stickHeader.reference);
    }
  }
};
</script>

<style lang="scss" scoped>
.fixed-top-helper {
  height: 1px;
  background: #ccc;
}
header {
  background: #ccc;
  &.fixed {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
  }
}
main {
  img {
    display: block;
    height: 500px;
    margin: 30px;
  }
}
footer {
  background: #ccc;
}
</style>
